package com.wang.springframework.beans.factory;

import com.wang.springframework.beans.BeansException;
import com.wang.springframework.beans.PropertyValue;
import com.wang.springframework.beans.PropertyValues;
import com.wang.springframework.beans.factory.config.BeanDefinition;
import com.wang.springframework.beans.factory.config.BeanFactoryPostProcessor;
import com.wang.springframework.core.io.DefaultResourceLoader;
import com.wang.springframework.core.io.Resource;
import com.wang.springframework.util.StringValueResolver;

import java.io.IOException;
import java.util.Properties;

/**
 * @author wangjianhua
 * @Description 允许从Configuration中配置单个bean属性值 即从一个properties文件中
 * 对于以系统管理员为目标的自定义配置文件很有用 这些文件覆盖在 application context中配置的bean属性
 * @date 2021/9/3/003 17:52
 **/
public class PropertyPlaceholderConfigurer implements BeanFactoryPostProcessor {

    public static final String DEFAULT_PLACEHOLDER_PREFIX = "${";

    public static final String DEFAULT_PLACEHOLDER_SUFFIX = "}";

    /**
     * 文件位置
     */
    private String location;



    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        //加载属性文件
        try
        {
            DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
            Resource resource = resourceLoader.getResource(location);
            Properties properties = new Properties();
            properties.load(resource.getInputStream());

            String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
            for (String beanName : beanDefinitionNames) {
                BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);

                PropertyValues propertyValues = beanDefinition.getPropertyValues();
                for (PropertyValue propertyValue : propertyValues.getPropertyValues()) {
                    Object value = propertyValue.getValue();
                    if(!(value instanceof String)){
                        continue;
                    }
                    value = resolvePlaceholder((String)value,properties);
                    propertyValues.addPropertyValue(new PropertyValue(propertyValue.getName(),value));
                }
            }

            //向容器中添加字符串解析器 供解析@Value注解使用
            StringValueResolver valueResolver = new PlaceholderResolvingStringValueResolver(properties);
            beanFactory.addEmbeddedValueResolver(valueResolver);
        }
        catch (IOException e)
        {
            throw new BeansException("Could not load properties",e);
        }
    }

    private String resolvePlaceholder(String value,Properties properties){
        StringBuilder builder = new StringBuilder(value);
        int startIdx = value.indexOf(DEFAULT_PLACEHOLDER_PREFIX);
        int stopIdx = value.indexOf(DEFAULT_PLACEHOLDER_SUFFIX);
        if(startIdx != -1 && stopIdx != -1 &&  startIdx < stopIdx){
            String propKey = value.substring(startIdx+2,stopIdx);
            String propVal = properties.getProperty(propKey);
            builder.replace(startIdx,stopIdx+1,propVal);

        }
        return builder.toString();
    }

    private class PlaceholderResolvingStringValueResolver implements StringValueResolver{

        private final Properties properties;

        public PlaceholderResolvingStringValueResolver(Properties properties) {
            this.properties = properties;
        }

        @Override
        public String resolveStringValue(String strVal) {
            return PropertyPlaceholderConfigurer.this.resolvePlaceholder(strVal,properties);
        }
    }

    public void setLocation(String location) {
        this.location = location;
    }
}
